﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using Singer.Middleware.RabbitMQ;
using System.Text;

namespace Singer.UintTestBackgroundJob.Examples;

/// <summary>
/// RabbitMQ后台任务 示例
/// </summary>
public class RabbitMQBackgroundJobExample : BackgroundService
{
    // 后台任务是单例的， 只能拿到单例的服务，拿作用域服务需要手动创建一个服务作用域

    IRabbitMQConnectionPool _rabbitMQConnectionPool;
    IModel _rabbitMQChannel;
    public RabbitMQBackgroundJobExample(IServiceProvider serviceProvider)
    {
        _rabbitMQConnectionPool = serviceProvider.GetRequiredService<IRabbitMQConnectionPool>();
        _rabbitMQChannel = _rabbitMQConnectionPool.Get().CreateModel();
    }

    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        EventingBasicConsumer consumer = new EventingBasicConsumer(_rabbitMQChannel);

        consumer.Received += async (sender, args) =>
        {
            string message = Encoding.UTF8.GetString(args.Body.ToArray());
            bool success = await OnMessageHandlerAsync(message);
            // 手动处理消息前提：取消自动应答机制（自动应答：收到消息即为确认消费成功）
            if (success)
            {
                // 任务执行成功，手动确认消息
                _rabbitMQChannel.BasicAck(deliveryTag: args.DeliveryTag, multiple: false); // 消息投递唯一标识、 是否批量确认
                Console.WriteLine("消息处理成功");
            }
            else
            {
                // 任务执行失败，拒绝消息，并让它重新进入队列，后面会再次消费
                _rabbitMQChannel.BasicNack(deliveryTag: args.DeliveryTag, multiple: false, requeue: true);// requeue：是否让消息重新回到队列。false时会放入死信队列
                Console.WriteLine("消息处理失败");
            }
        };
        _rabbitMQChannel.BasicConsume(queue: "queue_test1", autoAck: false, consumer); // 让消费者从指定的队列中消费消息，取消自动应答机制（）
        return Task.CompletedTask;
    }

    /// <summary>
    /// 消息处理任务
    /// </summary>
    /// <param name="message">接收的消息</param>
    /// <returns>消费任务是否执行成功</returns>
    private Task<bool> OnMessageHandlerAsync(string message)
    {
        Console.WriteLine(message);
        return Task.FromResult(true);
    }


    private new void Dispose()
    {
        base.Dispose();
        _rabbitMQChannel.Dispose();
    }
}
